StateObject anti-pattern info#21
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d2e2975eb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
It's better to say use such a thing with Parent View (Main View screen) because in such case it is valid useCase and will not break ownership lifeCycle. But don't say it is anti pattern because one of the core Philosophy of this skill is that we don't to force any specific pattern or way of writing code. |
|
It’s not valid, see the discussion. |
I saw the discussion and the thing is: when we init the @StateObject in the init of the View using StateObject(initial: _), all what we are doing is the following setting the default value of the State doing so doesn't break lifecycle of the State at all. What makes it a problem is when you expect the State to update when you change the value given to the view, but in case of you know that this is the parent view (Main View of the screen) and it takes a parameter as an input (not a state) and you use it in the init it's safe and valid approach, putting a side any architecture approach. See reference (StateObject is the same as State different is StateObject is for objects): |
|
I'm not sure where those pages are from but those pages and your explanation are the exact anti-pattern we need the skill to avoid. SwiftUI is the architecture and the architecture requires lifting the state into parent View and pass Binding down for write access (or let if its read only). Explained more in the discussion here: e.g. |
|
When you add a parameter (initial value ) for a view this doesn't mean we are removing the state from the parent view, all what it does is giving initial value of the state the same as the initial vale we put to the state after =. So Actually doing so has zero effect and it's a valid SwiftUI code that doesn't break the framework, maybe it's not the best architecture discussion and we don't include or force any architecture preferences in this skill. And by the way this book is created by objc.io specifically by chris eidhof. He is one of the top people in SwiftUI check him out. |
|
Passing an initial value to a child's @State creates a 'Split Source of Truth.' Once the child View is initialized, the parent can no longer update that value. The child 'owns' its own copy now, and the two will drift apart, creating a real mess to get back in sync. Could you show the specific use case you're working on? It's better to update the parent’s state before the child view appears, rather than trying to sync two separate states. And that can actually be tricky for someone new to SwiftUI, it might need the use of a struct or a computed Binding. |
|
I've made a snippet to play with based on ObjC SwiftUI example: import SwiftUI
struct Counter: View {
init(value: Int = 0) {
_value = State(wrappedValue: value)
}
@State private var value: Int
var body: some View {
Button("Increment: \(value)") {
value += 1
}
}
}
struct StateBindView: View {
@State private var value: Int = 0
var body: some View {
Divider()
Counter(value: value)
Divider()
Counter(value: value)
.id(value)
Divider()
Counter(value: 5)
Divider()
Button("Increment: \(value)") {
value += 1
}
}
}
#Preview {
StateBindView()
}As we can see, it decouples from rendering tree if we will use such init. Last paragraph says: it's not very useful. My suggestion: Let's remove "anti-pattern sentence" suggested by Codex. |
|
edited Here it is without anti-patterns: |
I am not talking about passing initial value to a child's @State in this case it's not good but I am talking about parent view in case of parent view this is a valid case and doesn't break anything and doesn't 'Split Source of Truth' because you are just giving initial value for the parent view. This is why it's valid to add it to this skill with that context in the skill. |
|
The goal of the example of the book is to show what the effect of doing such a thing to a child view but if the view is parent view it's valid to use it. I truly agree with all what you say, it's all right but for parent views it's a valid thing to do again butting aside any preferences. |
|
@EngOmarElsayed reading your comments it sounds like you generally agree that it's better to avoid using If so, can we change the contribution to cover the exact use cases where it's allowed, and make the Skill understand that it's better in general to not use it? |
Co-authored-by: Antoine van der Lee <4329185+AvdLee@users.noreply.github.com>
|
Thanks @lanserxt |



From discussion in previous PR: #7
Need to highlight in Skill that using such init, in general, is not very good pattern and breaks the logical scope.
CC @malhal